package com.itheima.wms.service.impl;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.pinda.base.entity.SuperEntity;
import com.itheima.wms.common.constants.CodeConstant;
import com.itheima.wms.common.enums.LocationStatus;
import com.itheima.wms.common.enums.LocationUseStatus;
import com.itheima.wms.common.service.CrudServiceImpl;
import com.itheima.wms.common.utils.RelationUtils;
import com.itheima.wms.common.constants.ConstantTable;
import com.itheima.wms.dao.*;
import com.itheima.wms.entity.AreaEntity;
import com.itheima.wms.entity.LocationEntity;
import com.itheima.wms.entity.OwnerLocationEntity;
import com.itheima.wms.entity.WarehouseEntity;
import com.itheima.wms.excel.model.AreaExcel;
import com.itheima.wms.factory.CodeWorker;
import com.itheima.wms.service.AreaService;
import com.itheima.wms.service.LocationService;
import com.itheima.wms.service.WarehouseService;
import com.itheima.wms.vo.AreaDetailVO;
import com.itheima.wms.vo.AreaOverviewVO;
import com.itheima.wms.vo.ImportResultVO;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;


/**
 * <p>
 * 业务实现类
 * 库区
 * </p>
 */
@Slf4j
@Service
public class AreaServiceImpl extends CrudServiceImpl<AreaMapper, AreaEntity> implements AreaService {

    private static List<Class> SERVICE = new ArrayList() {{
        add(LocationMapper.class);
        add(GoodsMapper.class);
        add(ReceiptMapper.class);
        add(OutboundMapper.class);
        add(CheckMapper.class);
    }};

    @Autowired
    private WarehouseService warehouseService;

    @Autowired
    @Lazy
    private LocationService locationService;

    @Autowired
    private OwnerLocationMapper ownerLocationMapper;

    @Override
    public List<AreaEntity> list(Map data) {
        if (data.containsKey("ownerId")) {
            Long ownerId = Long.valueOf(data.get("ownerId").toString());
            LambdaQueryWrapper<OwnerLocationEntity> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(OwnerLocationEntity::getOwnerId, ownerId);
            List<OwnerLocationEntity> ownerLocationEntities = ownerLocationMapper.selectList(wrapper);
            Set<Long> areaIdSet = ownerLocationEntities.stream().map(ownerLocationEntity -> ownerLocationEntity.getAreaId()).collect(Collectors.toSet());
            if (CollectionUtils.isEmpty(areaIdSet)) {
                return new ArrayList<>(0);
            }
            data.put("in_id", areaIdSet);
            data.remove("ownerId");
        }
        return super.list(data);
    }

    @Override
    public boolean save(AreaEntity entity) {
        boolean result = super.save(entity);
        if (result) {
            updateWarehouseCount(entity);
        }
        return result;
    }

    @Override
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        idList.forEach(id -> {
            RelationUtils.checkRelation(id, "area_id", SERVICE);

            AreaEntity entity = super.getById(id);
            updateWarehouseCount(entity);
        });
        return super.removeByIds(idList);
    }

    /**
     * 修改仓库的库区数量
     *
     * @param areaEntity
     * @return
     */
    private boolean updateWarehouseCount(AreaEntity areaEntity) {
        int count = this.count(getWrapper(AreaEntity::getWarehouseId, areaEntity.getWarehouseId()));
        LambdaUpdateWrapper<WarehouseEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(WarehouseEntity::getIncludedNum, count);
        updateWrapper.eq(SuperEntity::getId, areaEntity.getWarehouseId());
        return warehouseService.update(updateWrapper);
    }

    @Override
    public AreaOverviewVO overview(Long id) {
        AreaOverviewVO areaOverviewVO = new AreaOverviewVO();
        AreaEntity areaEntity = this.getById(id);
        LambdaQueryWrapper<LocationEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(LocationEntity::getAreaId, id);
        wrapper.eq(LocationEntity::getStatus, LocationStatus.DISABLE.getCode());
        int stop = locationService.count(wrapper);
        wrapper.clear();
        wrapper.eq(LocationEntity::getAreaId, id);
        wrapper.eq(LocationEntity::getStatus, LocationStatus.ENABLE.getCode());
        wrapper.ne(LocationEntity::getUseStatus, LocationUseStatus.FREE.getCode());
        int use = locationService.count(wrapper);
        wrapper.clear();
        wrapper.eq(LocationEntity::getAreaId, id);
        wrapper.eq(LocationEntity::getStatus, LocationStatus.ENABLE.getCode());
        wrapper.eq(LocationEntity::getUseStatus, LocationUseStatus.FREE.getCode());
        int free = locationService.count(wrapper);
        areaOverviewVO.setTotal(areaEntity.getIncludedNum());
        areaOverviewVO.setStop(stop);
        areaOverviewVO.setUse(use);
        areaOverviewVO.setFree(free);
        return areaOverviewVO;
    }


    @SneakyThrows
    @Override
    public ImportResultVO importExcel(MultipartFile file) {
        ImportParams importParams = new ImportParams();

        List<AreaExcel> areaExcels = ExcelImportUtil.importExcel(file.getInputStream(), AreaExcel.class, importParams);
        int total = areaExcels.size();
        log.debug("库区导入 解析文件:{} 条", total);

        TreeMap<Integer, String> resultMap = new TreeMap<>();
        for (int i = 0; i < areaExcels.size(); i++) {
            AreaExcel item = areaExcels.get(i);
            try {
                AreaEntity areaEntity = new AreaEntity();
                if (StringUtils.isBlank(item.getWarehouse())) {
                    resultMap.put((i + 1), "行" + (i + 1) + " 所属仓库为空");
                    continue;
                }
                WarehouseEntity warehouseEntity = warehouseService.getOne("name", item.getWarehouse());
                if (null == warehouseEntity || null == warehouseEntity.getId()) {
                    resultMap.put((i + 1), "行" + (i + 1) + " 所属仓库为空");
                    continue;
                }
                areaEntity.setWarehouseId(warehouseEntity.getId());

                if (StringUtils.isBlank(item.getWarehouse())) {
                    resultMap.put((i + 1), "行" + (i + 1) + " 库区名称为空");
                    continue;
                }
                areaEntity.setName(item.getName());

                String temperatureType = ConstantTable.TEMPERATURE_TYPE_CODE.get(item.getTemperatureType());
                if (StringUtils.isBlank(temperatureType)) {
                    resultMap.put((i + 1), "行" + (i + 1) + " 温度类型为空");
                    continue;
                }
                areaEntity.setTemperatureType(temperatureType);

                String bearingType = ConstantTable.BEARING_TYPE_CODE.get(item.getBearingType());
                if (StringUtils.isBlank(bearingType)) {
                    resultMap.put((i + 1), "行" + (i + 1) + " 承重类型为空");
                    continue;
                }
                areaEntity.setBearingType(bearingType);

                String type = ConstantTable.USE_TYPE_CODE.get(item.getType());
                if (StringUtils.isBlank(type)) {
                    resultMap.put((i + 1), "行" + (i + 1) + " 库区类型为空");
                    continue;
                }
                areaEntity.setType(type);

                String useType = ConstantTable.USE_TYPE_CODE.get(item.getUseType());
                if (StringUtils.isBlank(useType)) {
                    resultMap.put((i + 1), "行" + (i + 1) + " 用途类型为空");
                    continue;
                }
                areaEntity.setUseType(useType);

                Integer status = ConstantTable.STATUS_CODE.get(item.getStatus());
                if (null == status) {
                    resultMap.put((i + 1), "行" + (i + 1) + " 库区状态为空");
                    continue;
                }
                areaEntity.setStatus(status);

                if (StringUtils.isBlank(item.getPersonName())) {
                    resultMap.put((i + 1), "行" + (i + 1) + " 负责人为空");
                    continue;
                }
                areaEntity.setPersonName(item.getPersonName());

                areaEntity.setCode(CodeWorker.nextCode(CodeConstant.AREA));
                int flag = super.baseMapper.insert(areaEntity);
                if (flag <= 0) {
                    resultMap.put((i + 1), "行" + (i + 1) + " 库区导入失败");
                }
            } catch (Exception e) {
                if (e.getClass().getName().equals("org.springframework.dao.DuplicateKeyException")) {
                    resultMap.put((i + 1), "行" + (i + 1) + " 库区名称重复");
                } else {
                    log.warn("入库异常 {} ：", e.getClass().getName(), e);
                }
            }
        }

        ImportResultVO importResultVO = new ImportResultVO();
        importResultVO.setTotal(total);
        importResultVO.setFail(resultMap.values().size());
        importResultVO.setSuccess(total - importResultVO.getFail());
        importResultVO.setMessage(resultMap.values());
        return importResultVO;
    }

    @Override
    @Cacheable("AreaEntity")
    public AreaEntity getByName(String area) {
        return getOne("name", area);
    }

    @Override
    public IPage<AreaDetailVO> pageDetail(Page<AreaDetailVO> page, Map data) {
        IPage<AreaDetailVO> iPage = this.baseMapper.selectAreaDetail(page, data);
        return iPage;
    }
}

